/*
 * Systemprogrammierung
 * Multiplayer-Quiz
 *
 * Server
 *
 * main.c: Hauptprogramm des Servers
 */

#include "common/util.h"
#include "login.h"
#include "score.h"
#include "loader.h"
#include "catalog.h"
#include "user.h"
#include <getopt.h>
#include <stdio.h>
#include <fcntl.h>

int iPort = -1;

int main(int argc, char **argv) {
	setProgName(argv[0]);

	debugEnable();

	// check for single instance
	CheckServerInstance();

	// Unlink already linked shared memory
	loader_UnlinkSharedMemory();

	infoPrint("Server Gruppe Buchmaier/Heissenberger/Wolf gestartet!\n");

	user_InitMutex();

	// parse Kommandoparamet
	if (readArguments(argc, argv) != 0) {
		printf("Konnte Argumente nicht auslesen.");
	}
	if (catalog_GetCatalogDir() == NULL) {
		printf("\nKatalogverzeichniss wurde nicht gesetzt\n");
		printHelp();
		exit(0);
	} else {
		infoPrint("Catalog dir: %s ", catalog_GetCatalogDir());
	}

	// start loader process
	if (loader_StartLoader() != 0) {
		printf("Fehler beim Starten des Loaders!");
		exit(0);
	}

	// start score thread
	scoret_StartScoreThread();

	// start login thread
	login_StartLoginThread(iPort);
	return 0;
}

void printHelp() {
	printf("Aufruf: ./server -c KATALOG_VERZEICHNIS\n");
	printf("[-d] [-p PORT]\n");
	printf("Standard für LOADER_PFAD ist: ./loader\n");
	printf("Standard für PORT ist: 54321\n");
}

int readArguments(int argc, char **argv) {
	while (optind < argc) {
		int result = getopt(argc, argv, "-p:dc:");
		if (result == -1) { return 0; }
		switch (result) {
			case '?':
				fprintf(stderr, "Unbekannter Parameter.\n");
				printHelp();
				exit(0);

			case ':': /* parameter fehlt*/
				fprintf(stderr, "Fehlendes Argument.\n");
				printHelp();
				exit(0);
			case 'c': // Speicher Zeiger zum Katalogverzeichnis
				catalog_SetCatalogDir((char*)optarg);
				break;
			case 'p':
				if (65536 < atoi(optarg)) {
					infoPrint("Fehler: Port zu hoch (max: 65535)");
					exit(0);
				}
				else if (0 > atoi(optarg)) {
					infoPrint("Fehler: Port zu niedrig");
					exit(0);
				}
				iPort = atoi((char*)optarg);
				infoPrint("Port gesetzt: %d\n", iPort);
				break;
			case 'd':
				debugEnable();
				infoPrint("Debug an");
				break;
			default:
				fprintf(stderr, "Fehler in der Argumentenliste.\n");
				printHelp();
				exit(0);
		}
	}
	return 0;
}

void CheckServerInstance() {
	// erstelle File
	int file = open("/tmp/ServerLock", O_WRONLY | O_CREAT, 0644);
	struct flock lock;

	if (file < 0) {
		debugPrint("Konnte ServerLock nicht erstellen!\n");
		exit(1);
	}

	// setze Lock
	lock.l_type = F_WRLCK;
	lock.l_whence = SEEK_SET;
	lock.l_start = 0;
	lock.l_len = 0;

	// eine anderer Server läuft -> beende Applikation
	if (fcntl(file, F_SETLK, &lock) < 0) {
		infoPrint("Ein anderer Server läuft bereits! Beende...\n");
		exit(1);
	}
	if (ftruncate(file, 0) < 0) {
		infoPrint("Ein anderer Server läuft bereits! Beende...\n");
		exit(1);
	}
}
